﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using APNS.NET;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;

namespace APNSUnitTests.given_an_apnsconnectionpool
{

    public class when_I_get_a_connection
    {

        protected MockRepository mocks;
        protected Queue<IApnsConnection> connections;
        protected ApnsConnectionPool connectionPool;

        public virtual void Setup()
        {
            mocks = new MockRepository();
            connections = new Queue<IApnsConnection>();
            connectionPool = new ApnsConnectionPool(connections.Dequeue);
        }

        [TestClass]
        public class and_no_connections_are_in_the_pool : when_I_get_a_connection
        {
            
            [TestInitialize]
            public override void Setup()
            {
                base.Setup();
            }

            [TestMethod]
            public void then_a_new_connection_should_be_created()
            {
                var stubConnection = mocks.Stub<IApnsConnection>();
                stubConnection.Stub(c => c.Connected).Return(true);

                connections.Enqueue(stubConnection);
                mocks.ReplayAll();
                var connection = connectionPool.GetConnection();
                
                Assert.AreSame(stubConnection, connection);
                Assert.AreEqual(0, connections.Count);
            }
        }

        [TestClass]
        public class and_there_is_a_connection_in_the_pool : when_I_get_a_connection
        {

            [TestInitialize]
            public override void Setup()
            {
                base.Setup();
            }

            [TestMethod]
            public void then_the_existing_connection_should_be_returned()
            {
                var stubConnection = mocks.Stub<IApnsConnection>();
                stubConnection.Stub(c => c.Connected).Return(true);

                connections.Enqueue(stubConnection);

                // Put a connection in  the pool
                mocks.ReplayAll();
                connectionPool.ReleaseConnection(connectionPool.GetConnection(), false);

                // Get the connection out of the pool
                var connection = connectionPool.GetConnection();

                Assert.AreSame(stubConnection, connection);
                Assert.AreEqual(0, connections.Count);
            }
        }

        [TestClass]
        public class and_there_are_many_connections_in_the_pool : when_I_get_a_connection
        {

            [TestInitialize]
            public override void Setup()
            {
                base.Setup();
            }

            [TestMethod]
            public void then_the_existing_connections_should_be_returned()
            {
                var stubConnection1 = mocks.Stub<IApnsConnection>();
                var stubConnection2 = mocks.Stub<IApnsConnection>();

                stubConnection1.Stub(c => c.Connected).Return(true);
                stubConnection2.Stub(c => c.Connected).Return(true);

                connections.Enqueue(stubConnection1);
                connections.Enqueue(stubConnection2);

                // Put a connection in  the pool
                mocks.ReplayAll();
                var con1 = connectionPool.GetConnection();
                var con2 = connectionPool.GetConnection();

                connectionPool.ReleaseConnection(con1, false);
                connectionPool.ReleaseConnection(con2, false);

                // Get the connection out of the pool
                var connection1 = connectionPool.GetConnection();
                var connection2 = connectionPool.GetConnection();

                Assert.IsTrue(connection1 == stubConnection1 || connection1 == stubConnection2);
                Assert.IsTrue(connection2 == stubConnection1 || connection2 == stubConnection2);

                Assert.AreEqual(0, connections.Count);
            }
        }

    }
}
